home *** CD-ROM | disk | FTP | other *** search
- /* Listing 2 */
-
- /*****************************************************
- ADCDMA.C
-
- Routines for Data acquisition through DMA on the
- Lab Master AD.
-
- Copyright Don Bradley, 1991.
-
- Permission is granted for used of these routines
- in any manner as long as this copyright notice is
- included.
-
- Tested using Quick C 2.5 and MSC 6.0 on a
- Toshiba T5200.
-
- *****************************************************/
-
- #include <io.h>
- #include <errno.h>
- #include <conio.h>
-
- #include "dma.h"
- #include "labmastr.h"
-
- // DMA buffer
- static int far *dma_buffer;
-
- // DMA buffer index
- static unsigned int dma_buff_index;
- // previous DMA buffer index
- static unsigned int old_dma_buff_index;
-
- // number of conversions to collect
- static long num_to_collect;
- // number of conversions collected
- static long num_collected;
-
- // DMA finished flag
- static int dma_finished;
- // DMA channel number
- static int dma_chn;
-
- void (*process)(int);
-
- /*****************************************************
- init_adc_dma is a routine used for dma controlled
- analogue voltage input.
-
- called by:
-
- init_adc_dma(num_chn, num_samples, *freq, dma_chn,
- proc_func);
-
- where
-
- int num_chn # of channels to sample.
- Start channel is always
- chn 0. Thus chans collect
- are 0 ... num_chn-1
- long num_samples # of samples to collect.
- A sample is the group of
- channels
- double *freq Frequency of sampling in Hz.
- int dma_chn DMA channel number from 5-7.
- void(*proc_func)(int) process function to be
- called after each value is
- retrieved.
- *****************************************************/
- int init_adc_dma(unsigned int num_chn,
- long num_samples, double *freq, int dma_channel,
- void (*proc_func)(int))
- /*& Setup adc for dma transfer. */
- {
- long length;
- unsigned int i;
- unsigned int dma_mode;
-
- // check for proper passed values
- if (dma_channel < 5 || dma_channel > 7)
- return (0);
-
- dma_chn = dma_channel;
-
- disable_dma(dma_chn);
-
- disable_adc();
-
- if(num_chn > MAX_CHANNELS)
- return(FALSE);
-
- if (*freq == 0.0)
- return (FALSE);
-
- process = proc_func;
-
- /* create buffer for storing data in */
-
- if(!(dma_buffer = alloc_dma_buffer(dma_chn,
- ADC_DMA_BUFFER_LEN)))
- return (FALSE);
-
- clr_adc_dma_buffer();
-
- // Frequency adjusted for number of channels.
- // Next version will have a burst mode enabled.
- *freq *= num_chn;
-
- *freq = timerad(*freq);
-
- // Readjust frequency for number of channels.
- *freq /= num_chn;
-
-
- // Setup the channel gain array.
- for (i = 0; i < num_chn; i++) {
- outp(ADC_VIRTCHAN, i);
- outp(ADC_CHN_GAIN_ARRAY,
- ADC_GAIN_1 | ADC_BANK_0 | i);
- }
-
- // set adc control register
- outp(ADC_CONTROL, ADC_FIFO_ENABLE |
- ADC_SINGLE_ENDED | ((dma_chn - 4) << 2));
-
- outp(ADC_LASTCHAN, num_chn-1);
-
- // Start converstions at channel zero
- outp(ADC_VIRTCHAN, 0);
-
- num_to_collect = num_chn * num_samples;
- num_collected = 0L;
-
- length = (num_to_collect < (long)ADC_DMA_BUFFER_LEN) ?
- num_to_collect : (long)ADC_DMA_BUFFER_LEN;
-
- // Setup dma transfer.
- if(num_to_collect > (long)ADC_DMA_BUFFER_LEN)
- dma_mode = DMA_DEMAND_MODE | DMA_ADDRESS_INC |
- DMA_CONTINUOUS_ENABLE | DMA_ADC_TRANSFER;
- else
- dma_mode = DMA_DEMAND_MODE | DMA_ADDRESS_INC |
- DMA_CONTINUOUS_DISABLE | DMA_ADC_TRANSFER;
-
- dma(dma_chn, dma_mode, dma_buffer,
- (unsigned int) length);
-
- dma_finished = FALSE;
-
- return (TRUE);
- }
-
- void get_next_adc_values()
- /*& Returns the pointer to the next memory location,
- increments appropriate buffer pointers. */
- {
-
- if(dma_buffer[dma_buff_index] == NON_ADC_VALUE)
- return;
-
- // wait until sample has been recorded
- while(dma_buffer[dma_buff_index] != NON_ADC_VALUE) {
-
- // Check for overrun by looking at last adc
- // buffer location. If this location has a valid
- // adc value then an overrun has occurred. An
- // over run condtion will result in automatic
- // termination of adc collection. To detect an
- // overrun the number of samples collected will
- // be less than those requested.
-
- if(dma_buffer[old_dma_buff_index] != NON_ADC_VALUE) {
- terminate_adc_dma();
- return;
- }
-
- process(dma_buffer[dma_buff_index]);
-
- // clear collected value from DMA buffer
- dma_buffer[dma_buff_index] = NON_ADC_VALUE;
-
- // increment buffer pointer
- old_dma_buff_index = dma_buff_index;
- if (++dma_buff_index >= ADC_DMA_BUFFER_LEN)
- dma_buff_index = 0;
-
- // Increment number of conversions collected.
- // Used in automatic termination for repetitive
- // sampling under DMA.
- if(++num_collected >= num_to_collect) {
- terminate_adc_dma();
- return;
- }
- }
- }
-
- void terminate_adc_dma()
- /* Terminates adc dma collection. */
- {
- disable_dma(dma_chn);
- outp(ADC_CONTROL, 0);
-
- free_dma_buffer(dma_chn);
-
- dma_finished = TRUE;
- }
-
- void clr_adc_dma_buffer()
- /*& Clears the adc buffer to a non possible value. */
- {
- unsigned int i;
-
- for (i = 0; i < ADC_DMA_BUFFER_LEN; i++)
- dma_buffer[i] = NON_ADC_VALUE;
-
- dma_buff_index = 0;
- old_dma_buff_index = ADC_DMA_BUFFER_LEN-1;
- }
-
- int adc_dma_done(void)
- /*& Returns TRUE if all conversions are done. */
- {
- return(dma_finished);
- }
-
- long adc_dma_conversion_count()
- /*& Returns the number of samples collected. */
- {
- return(num_collected);
- }
-
-